<template>
  <div class="flow-setting-wrap">
    <div class="left">
      <ul class="header">
        <li class="name">工作流程设置</li>
        <li>状态</li>
      </ul>
      <ul class="flow-list">
        <template v-for="(item, i) in flowList" :key="i">
          <li :class="{ active: currentFlowIndex === i }">
            <div class="name" @click="changeFlow(i)">{{ item.approvalName }}</div>
            <div class="status">
              <a-popconfirm :content="`确定是否${item.status === 1 ? '关闭' : '开启'}${item.approvalName}流程`" @ok="changeState(item.status, item)" type="warning">
                <a-switch :disabled="!$authPass('user.approve.process.edit')" v-model="item.status" size="medium" :checked-value="1" :unchecked-value="0" :beforeChange="handleChangeIntercept">
                  <template #checked> 开 </template>
                  <template #unchecked> 关 </template>
                </a-switch>
              </a-popconfirm>
            </div>
          </li>
        </template>
      </ul>
    </div>
    <div class="right">
      <!-- <div class="header">审批流设置</div> -->
      <template v-if="isAllowSet">
        <div class="setting-w" v-if="flowDetail.processBranches">
          <div class="center-node-w">
            <div class="start-node">
              <p class="title">{{ flowDetail.approvalName }}开始</p>
              <div class="title-node">
                <span class="circle"></span>
                <span class="middle-line"></span>
                <a-button v-if="$authPass('user.approve.process.edit')" class="add-btn gray-outline" size="mini" shape="round" @click="addBranch">添加分支</a-button>
              </div>
            </div>
            <div class="center-node" v-if="flowDetail.processBranches.length">
              <div class="branch-w" v-for="(item, i) in flowDetail.processBranches" :key="i">
                <!-- 条件 -->
                <div class="node-w condition-node">
                  <div class="node-con">
                    <template v-if="item.branchType === 'OR'">
                      <div class="title flex-c-sb">
                        <p>条件{{ i + 1 }}</p>
                        <a-space class="edit-w">
                          <icon-delete v-if="$authPass('user.approve.process.edit')" @click="deleteBranch(i)" />
                          <icon-edit v-if="$authPass('user.approve.process.edit')" @click="openEdidnCondition(i)" />
                        </a-space>
                      </div>
                      <div class="condition-info" v-if="item.branchCondition">
                        <div class="line-w">
                          <div class="edit" :class="{ yellow: item.branchCondition.conditionType === 'ALL' }" @click="changeType(item.branchCondition)">
                            <span>{{ item.branchCondition.conditionType === 'ANY' ? '或' : '且' }}</span>
                            <icon-caret-down />
                          </div>
                        </div>
                        <div class="flex-c font-item">
                          <p>发起人：</p>
                          <div style="flex: 1" v-if="getNameStr(item.branchCondition.promoters, 'userName')">
                            <TextLimit :rows="1" :val="getNameStr(item.branchCondition.promoters, 'userName')" />
                          </div>
                          <p v-else>全部</p>
                        </div>
                        <div class="flex-c font-item">
                          <p>部门：</p>
                          <div style="flex: 1" v-if="getNameStr(item.branchCondition.promoterDepts, 'deptName')">
                            <TextLimit :rows="1" :val="getNameStr(item.branchCondition.promoterDepts, 'deptName')" />
                          </div>
                          <p v-else>全部</p>
                        </div>
                        <div class="flex-c font-item">
                          <p>角色：</p>
                          <div style="flex: 1" v-if="getNameStr(item.branchCondition.promoterRoles, 'roleName')">
                            <TextLimit :rows="1" :val="getNameStr(item.branchCondition.promoterRoles, 'roleName')" />
                          </div>
                          <p v-else>全部</p>
                        </div>
                        <div v-if="item.branchCondition.maxAmount || item.branchCondition.minAmount" class="flex-c font-item">
                          <p>金额：</p>
                          <p v-if="item.branchCondition.maxAmount && item.branchCondition.minAmount">{{ item.branchCondition.minAmount }} ~ {{ item.branchCondition.maxAmount }}</p>
                          <p v-else-if="item.branchCondition.maxAmount">小于{{ item.branchCondition.maxAmount }}</p>
                          <p v-else-if="item.branchCondition.minAmount">大于{{ item.branchCondition.minAmount }}</p>
                        </div>
                        <div class="flex-c font-item" v-if="getNameStr(item.branchCondition.suppliers, 'supplierName')">
                          <p>供应商：</p>
                          <TextLimit style="flex: 1" :rows="1" :val="getNameStr(item.branchCondition.suppliers, 'supplierName')" />
                        </div>
                        <div class="flex-c font-item" v-if="getNameStr(item.branchCondition.outWarehouses, 'warehouseName')">
                          <p>出库仓：</p>
                          <TextLimit style="flex: 1" :rows="1" :val="getNameStr(item.branchCondition.outWarehouses, 'warehouseName')" />
                        </div>
                        <div class="flex-c font-item" v-if="getNameStr(item.branchCondition.inWarehouses, 'warehouseName')">
                          <p>入库仓：</p>
                          <TextLimit style="flex: 1" :rows="1" :val="getNameStr(item.branchCondition.inWarehouses, 'warehouseName')" />
                        </div>
                        <div class="flex-c font-item" v-if="item.branchCondition.warehouseAttributes && item.branchCondition.warehouseAttributes.length">
                          <p>仓库属性：</p>
                          <p>{{ item.branchCondition.warehouseAttributes.map((val: string) => WarehouseAttributeMap[val]).join(',') }}</p>
                        </div>
                        <div class="flex-c font-item" v-if="getNameStr(item.branchCondition.warehouseManagers, 'userName')">
                          <p>仓管理员：</p>
                          <TextLimit style="flex: 1" :rows="1" :val="getNameStr(item.branchCondition.warehouseManagers, 'userName')" />
                        </div>
                        <div class="flex-c font-item" v-if="item.branchCondition.transTypes && item.branchCondition.transTypes.length">
                          <p>调拨类型：</p>
                          <TextLimit style="flex: 1" :rows="1" :val="item.branchCondition.transTypes.map((val: string) => TransTypesMap[val]).join(',')" />
                        </div>
                      </div>
                    </template>
                    <template v-else>
                      <div class="title">
                        <p>else</p>
                      </div>
                      <p style="margin-top: 5px" class="gray">如果左侧条件都不满足则直接执行本条</p>
                    </template>
                  </div>
                </div>
                <!-- 审核人 -->
                <template v-if="item.branchAudits && item.branchAudits.length">
                  <div class="node-w" v-for="(audit, j) in item.branchAudits" :key="j">
                    <div class="node-con">
                      <div class="title flex-c-sb">
                        <p>审核人：</p>
                        <icon-edit v-if="$authPass('user.approve.process.edit')" class="edit-w" @click="openDialog(i, 'showSetAuditor', j)" />
                      </div>
                      <div class="flex-wrap" style="margin-top: 5px">
                        <!-- 存在审批人 -->
                        <template v-if="hasAuditors(audit)">
                          <a-popover v-if="audit.auditorEnable && audit.auditors && audit.auditors.length" position="tl">
                            <p style="margin-right: 10px">指定成员</p>
                            <template #content>
                              <p style="max-width: 300px">{{ getNameStr(audit.auditors, 'userName') }}</p>
                            </template>
                          </a-popover>
                          <a-popover v-if="audit.auditRoleEnable && audit.auditRoles && audit.auditRoles.length" position="tl">
                            <p style="margin-right: 10px">指定角色</p>
                            <template #content>
                              <p style="max-width: 300px">{{ getNameStr(audit.auditRoles, 'roleName') }}</p>
                            </template>
                          </a-popover>
                          <a-popover v-if="audit.auditDeptTypeEnable && audit.auditDeptTypes && audit.auditDeptTypes.length" position="tl">
                            <p style="margin-right: 10px">指定发起人主管</p>
                            <template #content>
                              <p style="max-width: 300px">{{ audit.auditDeptTypes.map((el: any) => DeptType[el] || el).join(',') }}</p>
                            </template>
                          </a-popover>
                          <p style="margin-right: 10px" v-if="audit.appointWarehouseManager">指定仓库管理员</p>
                          <p style="color: #999">{{ AuditType[audit.auditType] }}</p>
                        </template>
                        <template v-else>
                          <p v-if="audit.noFindAuditorDealType == 'AUTO_PASS'">无审核人：自动通过</p>
                          <a-popover v-else position="tl">
                            <p style="margin-right: 10px">无审批人：指定成员</p>
                            <template #content>
                              <p style="max-width: 300px">{{ getNameStr(audit.appointAuditors, 'userName') }}</p>
                            </template>
                          </a-popover>
                        </template>
                      </div>
                    </div>
                  </div>
                </template>
                <!-- 抄送人 -->
                <div class="node-w">
                  <div class="node-con">
                    <div class="title flex-c-sb">
                      <p>抄送人：</p>
                      <icon-edit v-if="$authPass('user.approve.process.edit')" class="edit-w" @click="openDialog(i, 'showChooseCopyUser')" />
                    </div>
                    <div class="flex-c" style="margin-top: 5px">
                      <a-popover v-if="showCopyTo(item)" position="tl">
                        <p>{{ CopyToType[item.branchCopyTo.copyToType] }}</p>
                        <template #content>
                          <p style="max-width: 300px">{{ showCopyTo(item) }}</p>
                        </template>
                      </a-popover>
                      <p v-else>无抄送人</p>
                    </div>
                  </div>
                </div>
                <template v-if="i === 0 || i === flowDetail.processBranches.length - 1">
                  <span class="top-line" :class="i === 0 ? 'left' : 'right'"></span>
                  <span class="bottom-line" :class="i === 0 ? 'left' : 'right'"></span>
                </template>
              </div>
            </div>
            <div class="end-node">
              <div class="title-node">
                <span class="circle"></span>
                <span class="middle-line"></span>
              </div>
              <p class="title">审批流程结束</p>
            </div>
          </div>
        </div>
        <div class="handle-w" v-if="$authPass('user.approve.process.edit')">
          <a-popconfirm content="确认是否重置该审批流程?" @ok="resetFlow" type="error">
            <a-button>重置</a-button>
          </a-popconfirm>
          <a-button type="primary" :loading="submitLoading" @click="submitData">保存</a-button>
        </div>
      </template>
      <a-empty v-else>该审批流正在开发区中...</a-empty>
    </div>
  </div>
  <!-- 设置抄送人 -->
  <CopyRecipients v-if="showDialogMap.showChooseCopyUser" :copyInfo="flowDetail.processBranches[currentBranchIndex].branchCopyTo || {}" :isShow="showDialogMap.showChooseCopyUser" @closed="showDialogMap.showChooseCopyUser = false" @success="chooseCopyPerson" />
  <!-- 设置审批人 -->
  <SetAuditor v-if="showDialogMap.showSetAuditor" :auditInfo="currentAudit" :approvalType="flowDetail.approvalType" :isShow="showDialogMap.showSetAuditor" @closed="showDialogMap.showSetAuditor = false" @success="setAuditor" />
  <!-- 设置审批条件 -->
  <component v-if="showDialogMap.showEdidnCondition" :approvalType="flowDetail.approvalType" :conditionInfo="flowDetail.processBranches[currentBranchIndex].branchCondition || {}" :isShow="showDialogMap.showEdidnCondition" :index="currentBranchIndex" :is="componentList[componentName]" @closed="showDialogMap.showEdidnCondition = false" @success="chooseCondition" />
</template>

<script lang="ts" setup>
  import { onMounted, ref, computed } from 'vue'
  import { Message, Modal } from '@arco-design/web-vue'
  import CopyRecipients from './components/copyRecipients.vue'
  import SetAuditor from './components/setAuditor.vue'
  import PurchasePlanCondition from './components/purchasePlanCondition.vue'
  import PurchaseOrderCondition from './components/purchaseOrderCondition.vue'
  import OtherInAndOutOrderCondition from './components/otherInAndOutOrderCondition.vue'
  import TransferOrderCondition from './components/transferOrderCondition.vue'
  import supplierProductSpuClaimCondition from './components/supplierProductSpuClaimCondition.vue'
  import { AuditType, CopyToType, DeptType, WarehouseAttributeMap, TransTypesMap } from '@/views/workFlow/types'
  import { enableApprovalProcessConfig, findApprovalProcessConfig, getApprovalProcessTemplateByConfigId, updateApprovalProcessTemplate } from '@/api/workFlow'
  import { cloneDeep } from 'lodash-es'

  onMounted(getFlowList)
  // 判断是否开发审批流
  const flowList = ref<Array<any>>([])
  const submitLoading = ref(false)
  const currentFlowIndex = ref(0)
  const currentBranchIndex = ref(0) //当前分支节点
  const currentAuditIndex = ref(0) //当前分支节点
  const currentAudit = ref<any>({}) //当前审核节点信息
  const showDialogMap = ref<any>({
    showChooseCopyUser: false,
    showSetAuditor: false,
    showEdidnCondition: false,
  })
  const defaultElseBranch = {
    branchType: 'ELSE',
    branchAudits: [
      {
        auditType: 'ROUND',
        noFindAuditorDealType: 'AUTO_PASS',
        auditorEnable: false,
        auditRoleEnable: false,
        auditDeptTypeEnable: false,
      },
    ], //审核人
    branchCopyTo: { copyToType: 'APPOINT_USER' }, //抄送人
    branchCondition: { conditionType: 'ALL' }, //条件
  }
  const defaultConditionBranch = {
    branchType: 'OR',
    branchAudits: [
      {
        auditType: 'ROUND',
        noFindAuditorDealType: 'AUTO_PASS',
        auditorEnable: false,
        auditRoleEnable: false,
        auditDeptTypeEnable: false,
      },
    ], //审核人
    branchCopyTo: { copyToType: 'APPOINT_USER' }, //抄送人
    branchCondition: { conditionType: 'ALL' }, //条件
  }
  const flowDetail = ref<any>({
    processBranches: [],
  })
  const componentName = ref('PurchasePlanCondition')
  const componentNameMap = {
    PURCHASE_PLAN_ORDER_APPROVAL: 'PurchasePlanCondition',
    PURCHASE_ORDER_APPROVAL: 'PurchaseOrderCondition',
    OTHER_IN_ORDER_APPROVAL: 'OtherInAndOutOrderCondition',
    OTHER_OUT_ORDER_APPROVAL: 'OtherInAndOutOrderCondition',
    TRANSFER_ORDER_APPROVAL: 'TransferOrderCondition',
    SUPPLIER_PRODUCT_SPU_CLAIM_APPROVAL: 'supplierProductSpuClaimCondition', // 供应商产品认领审批，后期使用再更改
  }
  // 组件注册（伪注册）
  const componentList = {
    PurchasePlanCondition,
    PurchaseOrderCondition,
    OtherInAndOutOrderCondition,
    TransferOrderCondition,
    supplierProductSpuClaimCondition,
  }
  const isAllowSet = computed(() => {
    let name = componentNameMap[flowDetail.value.approvalType]
    return componentList.hasOwnProperty(name)
  })

  // 拦截自动切换
  function handleChangeIntercept() {
    return false
  }
  // 获取流程列表
  async function getFlowList() {
    const res: any = await findApprovalProcessConfig()
    flowList.value = res?.data || []
    if (flowList.value?.length) {
      currentFlowIndex.value = 0
      getFlowDetail()
    }
  }
  // 获取审批详情
  async function getFlowDetail() {
    let _id = flowList.value[currentFlowIndex.value]?.id
    const res: any = await getApprovalProcessTemplateByConfigId({ configId: _id })
    if (res?.data?.id) {
      flowDetail.value = res?.data
      if (!flowDetail.value.processBranches?.find((el: any) => el.branchType == 'ELSE')) {
        flowDetail.value.processBranches.push(cloneDeep(defaultElseBranch))
      }
    } else {
      flowDetail.value = { ...flowList.value[currentFlowIndex.value] }
      flowDetail.value.configId = flowDetail.value.id
      flowDetail.value.processBranches = [cloneDeep(defaultConditionBranch), cloneDeep(defaultElseBranch)]
    }
  }
  // 修改审批流程状态
  async function changeState(state: any, item: any) {
    let status = state === 1 ? 0 : 1
    const res: any = await enableApprovalProcessConfig({
      id: item.id,
      status: status,
    })
    if (res) {
      Message.success('更新成功！')
      item.status = status
    }
  }
  // 存在审批人
  function hasAuditors(row: any) {
    // 选择了审核人或者审核人不存在时
    return (row.auditorEnable && row.auditors?.length) || (row.auditRoleEnable && row.auditRoles?.length) || (row.auditDeptTypeEnable && row.auditDeptTypes?.length) || row.appointWarehouseManager
  }

  // 显示抄送人
  function showCopyTo(row: any) {
    let val = ''
    let type = row.branchCopyTo?.copyToType
    let copyInfo = row.branchCopyTo || {}
    if (type == 'APPOINT_USER') {
      val = copyInfo.copyToUsers?.map((el: any) => el.userName)?.join(',')
    } else if (type == 'APPOINT_ROLE') {
      val = copyInfo.copyToRoles?.map((el: any) => el.roleName)?.join(',')
    } else if (type == 'APPOINT_MANAGER') {
      val = copyInfo.copyToDeptTypes?.map((el: any) => DeptType[el] || el)?.join(',')
    }
    return val
  }
  // 切换流程
  function changeFlow(i: number) {
    currentFlowIndex.value = i
    getFlowDetail()
  }
  // 添加条件分支
  function addBranch() {
    flowDetail.value.processBranches.splice(1, 0, cloneDeep(defaultConditionBranch))
  }
  // 删除分支
  function deleteBranch(i: number) {
    if (flowDetail.value.processBranches.length < 3) {
      Message.error('请最少保留一个条件！')
      return
    }
    Modal.confirm({
      title: '确认',
      content: `请再次确认是否删除条件${i + 1}?`,
      cancelText: '取消',
      okText: '确认',
      onOk: () => {
        flowDetail.value.processBranches.splice(i, 1)
      },
    })
  }
  // 切换条件类型
  function changeType(info: any) {
    info.conditionType = info.conditionType === 'ANY' ? 'ALL' : 'ANY'
  }
  // 显示用户或者部门列表
  function getNameStr(list: Array<any>, key: string) {
    let vals = list?.map((item: any) => item[key])
    vals = vals?.filter((i: any) => i)
    if (!vals?.length) return ''
    return vals?.join(',')
  }

  // 重置审批流程
  function resetFlow() {
    flowDetail.value = { ...flowList.value[currentFlowIndex.value] }
    flowDetail.value.configId = flowDetail.value.id
    flowDetail.value.processBranches = [cloneDeep(defaultConditionBranch), cloneDeep(defaultElseBranch)]
  }

  // 打开设置
  function openDialog(i: number, key: string, j?: number) {
    currentBranchIndex.value = i
    currentAuditIndex.value = j || 0
    currentAudit.value = flowDetail.value.processBranches[i].branchAudits[currentAuditIndex.value]
    showDialogMap.value[key] = true
  }
  // 设置抄送人
  function chooseCopyPerson(info: any) {
    flowDetail.value.processBranches[currentBranchIndex.value].branchCopyTo = info
  }
  // 设置审批人
  function setAuditor(info: any) {
    flowDetail.value.processBranches[currentBranchIndex.value].branchAudits[currentAuditIndex.value] = info
  }
  // 打开条件设置
  function openEdidnCondition(i: number) {
    currentBranchIndex.value = i
    componentName.value = componentNameMap[flowDetail.value.approvalType]
    showDialogMap.value.showEdidnCondition = true
  }
  // 设置条件
  function chooseCondition(info: any) {
    flowDetail.value.processBranches[currentBranchIndex.value].branchCondition = info
  }
  // 更新配置
  async function submitData() {
    let indexs: Array<number> = []
    flowDetail.value.processBranches.forEach((item: any, index: number) => {
      if (item.branchAudits.find((el: any) => !hasAuditors(el) && el.noFindAuditorDealType == 'AUTO_PASS')) {
        indexs.push(index)
      }
    })
    if (indexs.length) {
      let msgs = indexs.map((i: number) => (i === flowDetail.value.processBranches.length - 1 ? 'else' : `条件${i + 1}`))
      Modal.confirm({
        title: '提示',
        content: `【${msgs.join(',')}】未设置审核人，符合该条件的单据将直接审核通过，请再次确认是否保存？`,
        cancelText: '取消',
        okText: '确认',
        onOk: () => {
          requestUpdate()
        },
      })
    } else {
      requestUpdate()
    }
  }
  async function requestUpdate() {
    submitLoading.value = true
    const res: any = await updateApprovalProcessTemplate(flowDetail.value)
    submitLoading.value = false
    if (res) {
      Message.success('审批流模板更新成功！')
    }
  }
</script>

<style lang="less" scoped>
  .flow-setting-wrap {
    height: calc(100vh - @menuHeight);
    display: flex;
    background-color: var(--color-fill-2);
    // background-color: #fff;
    .left {
      height: 100%;
      background-color: #fff;
      border-right: 1px solid #ddd;
      flex-shrink: 0;
      .header {
        background-color: var(--color-fill-2);
        display: flex;
        border-bottom: 1px solid #ddd;
        li {
          line-height: 36px;
          text-align: center;
          padding: 0 5px;
          width: 80px;
          &.name {
            width: 150px;
            border-right: 1px solid #ddd;
          }
        }
      }
    }
    .flow-list {
      li {
        display: flex;
        line-height: 36px;
        text-align: center;
        border-bottom: 1px solid #ddd;

        .name {
          width: 150px;
          border-right: 1px solid #ddd;
          padding: 0 5px;
          color: var(--color-text-3);
        }
        .status {
          width: 80px;
        }
        &.active {
          background-color: rgb(var(--primary-2));
          .name {
            color: var(--color-text-1);
          }
        }
      }
    }
    .right {
      flex: 1;
      display: flex;
      flex-direction: column;
      overflow: hidden;
      .header {
        line-height: 36px;
        text-align: center;
        background-color: #fff;
        border-bottom: 1px solid #ddd;
      }
      .setting-w {
        flex: 1;
        overflow: auto;
        text-align: center;

        .center-node-w {
          padding: 110px 10px 90px;
          position: relative;
          display: inline-block;
        }
        .center-node {
          border-top: 2px solid #ddd;
          border-bottom: 2px solid #ddd;
          display: flex;
          .branch-w {
            position: relative;
            padding: 20px 0;
            &::before {
              content: '';
              position: absolute;
              top: 0;
              left: 0;
              right: 0;
              bottom: 0;
              margin: auto;
              width: 2px;
              height: 100%;
              background-color: #ddd;
            }
            .top-line,
            .bottom-line {
              display: inline-block;
              width: 50%;
              background-color: var(--color-fill-2);
              height: 4px;
              position: absolute;
              top: -3px;
              &.left {
                left: 0;
              }
              &.right {
                right: 0;
              }
            }
            .bottom-line {
              top: auto;
              bottom: -3px;
            }
          }
          .node-w {
            padding: 20px;
            position: relative;
            text-align: left;

            .node-con {
              position: relative;
              width: 260px;
              padding: 5px 5px 10px;
              font-size: 12px;
              background-color: #fff;
              border-radius: 5px;
              color: #666;
              min-height: 80px;
              .title {
                font-weight: bold;
                height: 30px;
                background: linear-gradient(to right, rgb(var(--warning-2)), rgb(var(--warning-1)));
                padding: 0 5px;
                color: rgb(var(--warning-6));

                .arco-icon {
                  font-size: 14px;
                  cursor: pointer;
                }
              }
              .edit-w {
                display: none;
              }

              &:hover {
                box-shadow: 0 0 6px 2px #ddd;
                .edit-w {
                  display: flex;
                }
              }
            }
            &.condition-node {
              min-height: 175px;
              .node-con {
                .title {
                  color: rgb(var(--primary-6));
                  background: linear-gradient(to right, rgb(var(--primary-2)), rgb(var(--primary-1)));
                }
              }
            }
          }
        }
        .condition-info {
          padding-left: 34px;
          position: relative;
          padding-top: 10px;
          .line-w {
            border: 1px solid rgb(var(--primary-5));
            border-radius: 5px 0 0 5px;
            width: 20px;
            position: absolute;
            top: 22px;
            bottom: 12px;
            left: 10px;
            border-right: none;
            .edit {
              position: absolute;
              top: 50%;
              left: -14px;
              transform: translate(0, -50%);
              background-color: rgb(var(--primary-6));
              color: #fff;
              font-size: 10px;
              width: 28px;
              border-radius: 5px;
              text-align: center;
              cursor: pointer;
              &.yellow {
                background-color: rgb(var(--warning-6));
              }
            }
          }
          .font-item {
            line-height: 26px;
          }
        }
        .start-node,
        .end-node {
          text-align: center;
          position: absolute;
          left: 50%;
          transform: translate(-50%);
        }
        .start-node {
          top: 10px;
        }
        .end-node {
          bottom: 10px;
        }
        .title-node {
          height: 80px;
          position: relative;
          .circle {
            display: inline-block;
            width: 15px;
            height: 15px;
            border-radius: 50%;
            border: 2px solid #ddd;
            background-color: #fff;
            position: absolute;
            top: 0;
            left: 50%;
            transform: translate(-50%);
            z-index: 10;
          }
          .middle-line {
            position: absolute;
            top: 0;
            left: 50%;
            width: 2px;
            height: 100%;
            transform: translate(-50%);
            background-color: #ddd;
          }
          .add-btn {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background-color: #fff;
          }
        }
        .end-node {
          .title-node {
            height: 60px;
            .circle {
              bottom: 0;
              top: auto;
            }
          }
        }
      }
      .handle-w {
        text-align: center;
        padding: 10px;
        background-color: #fff;
        .arco-btn {
          margin: 0 20px;
        }
      }
    }
  }
</style>
